From 4ac89686e88c949370751d71483902c3e526611b Mon Sep 17 00:00:00 2001 From: oliskoli Date: Wed, 13 Dec 2006 21:52:09 +0000 Subject: [PATCH] Add option "grid" and "British National Grid" to supported grids (Feature req. 1557425). --- garmin_txt.c | 221 ++++++++++++++++----- xmldoc/formats/options/garmin_txt-grid.xml | 15 ++ 2 files changed, 189 insertions(+), 47 deletions(-) create mode 100644 xmldoc/formats/options/garmin_txt-grid.xml diff --git a/garmin_txt.c b/garmin_txt.c index 9de5d56e7..20aae4cd6 100644 --- a/garmin_txt.c +++ b/garmin_txt.c @@ -96,12 +96,14 @@ static char *opt_date_format = NULL; static char *opt_time_format = NULL; static char *opt_precision = NULL; static char *opt_utc = NULL; +static char *opt_grid = NULL; static arglist_t garmin_txt_args[] = { {"date", &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", NULL, ARGTYPE_STRING, ARG_NOMINMAX}, {"datum", &opt_datum, "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX}, {"dist", &opt_dist, "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX}, + {"grid", &opt_grid, "Write position using this grid.", NULL, ARGTYPE_STRING, ARG_NOMINMAX}, {"prec", &opt_precision, "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX}, {"temp", &opt_temp, "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX}, {"time", &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", NULL, ARGTYPE_STRING, ARG_NOMINMAX}, @@ -137,6 +139,26 @@ static char *headers[] = { NULL }; +static char *grid_short_names[] = { + "ddd", + "dmm", + "dms", + "bng", + NULL +}; + +static char *grid_long_names[] = { /* starting at index !!! 3 !!! after inbuild lat/lon ... grids */ + "British National Grid", + NULL +}; + +#define GRID_IDX_LAT_LON_DDD 0 +#define GRID_IDX_LAT_LON_DMM 1 +#define GRID_IDX_LAT_LON_DMS 2 +#define GRID_IDX_BNG 3 + +#define GRID_IDX_MAX GRID_IDX_BNG + /* helpers */ static char * @@ -313,30 +335,59 @@ prework_wpt_cb(const waypoint *wpt) static void print_position(const waypoint *wpt) { - int deg; - double min; - char num[64]; - double lat, lon; + int valid; + double lat, lon, north, east; + char map[3]; + char latsig, lonsig; + double latmin, lonmin, latsec, lonsec; + int latint, lonint; convert_datum((waypoint *)wpt, 0, &lat, &lon); - deg = fabs(lat); - min = (double)60.0 * (fabs(lat) - deg); - snprintf(num, sizeof(num), "%0*.*f", precision + 3, precision, min); - if (atoi(num) == 60) { - deg++; - min = 0; - } - gbfprintf(fout, "%c%d %0*.*f ", lat < 0.0 ? 'S' : 'N', deg, precision + 3, precision, min); - - deg = fabs(lon); - min = (double)60.0 * (fabs(lon) - deg); - snprintf(num, sizeof(num), "%0*.*f", precision + 3, precision, min); - if (atoi(num) == 60) { - deg++; - min = 0; + /* ----------------------------------------------------------------------------*/ + /* the following code is from pretty_deg_format (util.c) */ + /* ----------------------------------------------------------------------------*/ + /* !ToDo! generate common code for calculating of degrees, minutes and seconds */ + /* ----------------------------------------------------------------------------*/ + + latsig = lat < 0 ? 'S':'N'; + lonsig = lon < 0 ? 'W':'E'; + latint = abs((int) lat); + lonint = abs((int) lon); + latmin = 60.0 * (fabs(lat) - latint); + lonmin = 60.0 * (fabs(lon) - lonint); + latsec = 60.0 * (latmin - floor(latmin)); + lonsec = 60.0 * (lonmin - floor(lonmin)); + + switch(grid_index) { + + case GRID_IDX_LAT_LON_DDD: + + gbfprintf(fout, "%c%0.*f %c%0.*f\t", + latsig, precision, fabs(lat), + lonsig, precision, fabs(lon)); + break; + + case GRID_IDX_LAT_LON_DMM: + + gbfprintf(fout, "%c%d %0*.*f %c%d %0*.*f\t", + latsig, latint, precision + 3, precision, latmin, + lonsig, lonint, precision + 3, precision, lonmin); + break; + + case GRID_IDX_LAT_LON_DMS: + + gbfprintf(fout, "%c%d %d %.*f %c%d %d %.*f\t", + latsig, latint, (int)latmin, precision, latsec, + lonsig, lonint, (int)lonmin, precision, lonsec); + break; + + case GRID_IDX_BNG: + valid = GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map); + is_fatal(! valid, MYNAME ": Some (or all?) of the coordinates cannot be displayed using \"BNG\"."); + gbfprintf(fout, "%s %5.0f %5.0f", map, east, north); + break; } - gbfprintf(fout, "%c%d %0*.*f\t", lon < 0.0 ? 'W' : 'E', deg, precision + 3, precision, min); } static void @@ -691,10 +742,11 @@ track_disp_wpt_cb(const waypoint *wpt) static void garmin_txt_wr_init(const char *fname) { + char *grid_str; + memset(>xt_flags, 0, sizeof(gtxt_flags)); fout = gbfopen(fname, "wb", MYNAME); - grid_index = 1; gtxt_flags.metric = (toupper(*get_option_val(opt_dist, "m")) == 'M'); gtxt_flags.celsius = (toupper(*get_option_val(opt_temp, "c")) == 'C'); @@ -703,9 +755,47 @@ garmin_txt_wr_init(const char *fname) precision = atoi(opt_precision); is_fatal(precision < 0, MYNAME ": Invalid precision (%s)!", opt_precision); } + datum_str = get_option_val(opt_datum, NULL); - datum_index = GPS_Lookup_Datum_Index(datum_str); - is_fatal(datum_index < 0, MYNAME ": Invalid or unknown gps datum (%s)!", datum_str); + grid_str = get_option_val(opt_grid, NULL); + + grid_index = -1; + if (grid_str == NULL) { + grid_index = 1; /* default: dmm */ + } + else if (! sscanf(grid_str, "%d", &grid_index)) { + char *name; + int index; + + index = 0; + while ((name = grid_short_names[index])) { + if (case_ignore_strcmp(name, grid_str) == 0) { + grid_index = index; + break; + } + index++; + } + if (name == NULL) { /* look in "long names" */ + index = 0; + while ((name = grid_long_names[index])) { + if (case_ignore_strcmp(name, grid_str) == 0) break; + else index++; + } + is_fatal(name == NULL, + MYNAME ": Unsupported grid (%s). See GPSBabel help for supported grids.", grid_str); + grid_index = 3 + index; + } + } + else is_fatal(grid_index > GRID_IDX_MAX, MYNAME ": Grid index out of range (0..%d)!", GRID_IDX_MAX); + + switch(grid_index) { + case GRID_IDX_BNG: /* force datum to "Ord Srvy Grt Britn" */ + datum_index = GPS_Lookup_Datum_Index("OSGB36"); + break; + default: + datum_index = GPS_Lookup_Datum_Index(datum_str); + is_fatal(datum_index < 0, MYNAME ": Invalid or unknown gps datum (%s)!", datum_str); + } if (opt_utc != NULL) { if (case_ignore_strcmp(opt_utc, "utc") == 0) @@ -727,7 +817,22 @@ garmin_txt_wr_deinit(void) static void garmin_txt_write(void) { - cet_gbfprintf(fout, &cet_cs_vec_cp1252, "Grid\tLat/Lon hddd%cmm.mmm'\r\n", 0xB0); + switch(grid_index) { + case 0: + cet_gbfprintf(fout, &cet_cs_vec_cp1252, "Grid\tLat/Lon hddd.ddddd%c\r\n", 0xB0); + break; + case 1: + cet_gbfprintf(fout, &cet_cs_vec_cp1252, "Grid\tLat/Lon hddd%cmm.mmm'\r\n", 0xB0); + break; + case 2: + cet_gbfprintf(fout, &cet_cs_vec_cp1252, "Grid\tLat/Lon hddd%cmm'ss.s\"\r\n", 0xB0); + break; + case GRID_IDX_BNG: + cet_gbfprintf(fout, &cet_cs_vec_cp1252, "Grid\t%s\r\n", grid_long_names[0]); + datum_str = "Ord Srvy Grt Britn"; + break; + } + gbfprintf(fout, "Datum\t%s\r\n\r\n", datum_str); waypoints = 0; @@ -803,23 +908,31 @@ static void parse_position(const char *str, waypoint *wpt) { double lat, lon; - unsigned char lathemi, hemilon; + unsigned char lathemi, lonhemi; int deg_lat, deg_lon, min_lat, min_lon; + char map[3]; switch(grid_index) { - case 0: - sscanf(str, "%c%lf %c%lf", &lathemi, &lat, &hemilon, &lon); - break; - case 1: - sscanf(str, "%c%d %lf %c%d %lf", &lathemi, °_lat, &lat, &hemilon, °_lon, &lon); - lat = (double)deg_lat + (lat / (double)60); - lon = (double)deg_lon + (lon / (double)60); - break; - case 2: - sscanf(str, "%c%d %d %lf %c%d %d %lf", &lathemi, °_lat, &min_lat, &lat, &hemilon, °_lon, &min_lon, &lon); - lat = (double)deg_lat + ((double)min_lat / (double)60) + (lat / (double)3600.0); - lon = (double)deg_lon + ((double)min_lon / (double)60) + (lon / (double)3600.0); - break; + + case GRID_IDX_LAT_LON_DDD: + sscanf(str, "%c%lf %c%lf", &lathemi, &lat, &lonhemi, &lon); + break; + + case GRID_IDX_LAT_LON_DMM: + sscanf(str, "%c%d %lf %c%d %lf", &lathemi, °_lat, &lat, &lonhemi, °_lon, &lon); + lat = (double)deg_lat + (lat / (double)60); + lon = (double)deg_lon + (lon / (double)60); + break; + case GRID_IDX_LAT_LON_DMS: + sscanf(str, "%c%d %d %lf %c%d %d %lf", &lathemi, °_lat, &min_lat, &lat, &lonhemi, °_lon, &min_lon, &lon); + lat = (double)deg_lat + ((double)min_lat / (double)60) + (lat / (double)3600.0); + lon = (double)deg_lon + ((double)min_lon / (double)60) + (lon / (double)3600.0); + break; + + case GRID_IDX_BNG: + sscanf(str, "%2s %lf %lf", map, &lat, &lon); + lathemi = lonhemi = '\0'; + break; } if (lathemi == 'S') @@ -827,7 +940,7 @@ parse_position(const char *str, waypoint *wpt) else wpt->latitude = lat; - if (hemilon == 'W') + if (lonhemi == 'W') wpt->longitude = -lon; else wpt->longitude = lon; @@ -1024,12 +1137,26 @@ bind_fields(const header_type ht) static void parse_grid(void) { + grid_index = -1; + char *str = csv_lineparse(NULL, "\t", "", 1); if (str != NULL) { - if (strstr(str, "dd.ddddd") != 0) grid_index = 0; - else if (strstr(str, "mm.mmm") != 0) grid_index = 1; - else if (strstr(str, "mm'ss.s") != 0) grid_index = 2; - else fatal(MYNAME ": Unsupported grid (%s)!\n", str); + if (strstr(str, "dd.ddddd") != 0) grid_index = GRID_IDX_LAT_LON_DDD; + else if (strstr(str, "mm.mmm") != 0) grid_index = GRID_IDX_LAT_LON_DMM; + else if (strstr(str, "mm'ss.s") != 0) grid_index = GRID_IDX_LAT_LON_DMS; + else { + char *name; + int index = 0; + + while ((name = grid_long_names[index])) { + if (case_ignore_strcmp(name, str) == 0) { + grid_index = GRID_IDX_BNG + index; + break; + } + index++; + } + } + is_fatal(grid_index < 0, MYNAME ": Unsupported grid (%s)!", str); } else fatal(MYNAME ": Missing grid headline!\n"); @@ -1196,7 +1323,7 @@ parse_track_waypoint(void) /***************************************************************/ static void -garmin_rd_init(const char *fname) +garmin_txt_rd_init(const char *fname) { memset(>xt_flags, 0, sizeof(gtxt_flags)); @@ -1210,7 +1337,7 @@ garmin_rd_init(const char *fname) } static void -garmin_rd_deinit(void) +garmin_txt_rd_deinit(void) { header_type h; @@ -1258,9 +1385,9 @@ garmin_txt_read(void) ff_vecs_t garmin_txt_vecs = { ff_type_file, FF_CAP_RW_ALL, - garmin_rd_init, + garmin_txt_rd_init, garmin_txt_wr_init, - garmin_rd_deinit, + garmin_txt_rd_deinit, garmin_txt_wr_deinit, garmin_txt_read, garmin_txt_write, diff --git a/xmldoc/formats/options/garmin_txt-grid.xml b/xmldoc/formats/options/garmin_txt-grid.xml new file mode 100644 index 000000000..e13487233 --- /dev/null +++ b/xmldoc/formats/options/garmin_txt-grid.xml @@ -0,0 +1,15 @@ + + This value specifies the grid to be used on write. + + +# idx short file-header sample + 0 ddd Lat/Lon hddd.ddddd S26.25333 E27.92333 + 1 dmm Lat/Lon hddd°mm.mmm N33 56.539 W118 24.471 + 2 dms Lat/Lon hddd°mm'ss.s" S25 25 26.8 E28 06 07.3 + 3 bng British National Grid TQ 18919 69392 + + + Idx or short are valid params for this option. + + + -- 2.30.2